[bash] the <<<$DATA issue

When I need to modify vars inside while loop, I try to use <<<$DATA
instead of <file form. I hit the problem with the <<<$DATA form, as
follows.

Generally, the following two forms are expected to be equivalent,
no ?:

1) while read x; do ... ; done <file
2) DATA="`cat <file`"; while read x; do ... ; done <<<"$DATA"

Except for the case when file is empty. Then 2nd form does not work
right for me:
a)
while read x; do echo "<<X>>"; done </dev/null
# correct: does not print anything
b)
DATA="`cat </dev/null`"; while read x; do echo "<<$x>>" ; done
<<<"$DATA"
# wrong: prints <<>> once

Why second form enters the loop once in (b) ? Is it a bash bug ?

Thanks
G.G.
guisep4 [ Fr, 11 Januar 2008 18:06 ] [ ID #1905105 ]

Re: [bash] the <<<$DATA issue

On Fri, 11 Jan 2008 09:06:28 -0800 (PST), guisep4 [at] gmail.com wrote:
> When I need to modify vars inside while loop, I try to use <<<$DATA
> instead of <file form. I hit the problem with the <<<$DATA form, as
> follows.
>
> Generally, the following two forms are expected to be equivalent,
> no ?:
>
> 1) while read x; do ... ; done <file
> 2) DATA="`cat <file`"; while read x; do ... ; done <<<"$DATA"
>
> Except for the case when file is empty. Then 2nd form does not work
> right for me:
> a)
> while read x; do echo "<<X>>"; done </dev/null
> # correct: does not print anything
> b)
> DATA="`cat </dev/null`"; while read x; do echo "<<$x>>" ; done
> <<<"$DATA"
> # wrong: prints <<>> once
>
> Why second form enters the loop once in (b) ? Is it a bash bug ?
[...]

because otherwise

read foo <<< bar

wouldn't put anything into $foo.

The cmd <<< xxx syntax (that comes from the "rc" shell, through
zsh), stores "xxx" followed by a NL character into a temporary
file and opens that file for reading as the standard input of
cmd.

$ od -c <<< ''
0000000 \n
0000001

The thing is that for non-empty files,

foo=`cat < file`

removes the trailing NLs (yes all of them, however strange and
inapropriate that may seem), and <<< restores one.

For an empty file, there's no NL that `...` may remove and <<<
adds one nonetheless.

You could do instead:

data=`cat < "$file"; echo .`; data=${data%.}
# that stores the content of the file exactly as long as it
# doesn't contain NUL bytes (except for zsh that supports NUL
# bytes.

and then:

printf %s "$data" | {
while IFS= read -r line; do
printf '<<%s>>\n' "$line";
done
if [ -n "$line" ]; then
printf 'There was something after the last NL: <<%s>>\n' "$line"
fi
}

Another illustration of why you should avoid "while read" loops.

--
Stephane
Stephane CHAZELAS [ Fr, 11 Januar 2008 20:17 ] [ ID #1905108 ]

Re: [bash] the <<<$DATA issue

On 11 Jan 2008 19:17:04 GMT, Stephane Chazelas wrote:
[...]
>> 2) DATA="`cat <file`"; while read x; do ... ; done <<<"$DATA"
[...]
>> Why second form enters the loop once in (b) ? Is it a bash bug ?
> [...]
>
> because otherwise
>
> read foo <<< bar
>
> wouldn't put anything into $foo.
[...]

Well, it would put "bar" in $foo, but would return false because
it didn't manage to read a full line (that is, up to the
terminating NL).

--
Stephane
Stephane CHAZELAS [ Fr, 11 Januar 2008 20:26 ] [ ID #1905109 ]
Linux » comp.unix.shell » [bash] the <<<$DATA issue

Vorheriges Thema: shell script - generate a report with dir and # files
Nächstes Thema: plotting from the shell